#include <iostream>
#include <ctype.h>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <cstring>
#include <unordered_map>
#include <sys/stat.h>
#include <fcntl.h>
// 全局变量
#define HOST_NAME 256
#define FORMAT "[%s@%s:%s]# "
#define COMMANDLINE 256
#define ARGV_MAX 128
char hostName[HOST_NAME];
int g_argc = 0;
char* g_argv[ARGV_MAX];
int lastcode = 0;
#define MAX_ENVS 100
char *g_env[MAX_ENVS];
int g_envs = 0;
// 关于重定向的宏
#define NONE_REDIR 0
#define INPUT_REDIR 1
#define OUTPUT_REDIR 2
#define APPEND_REDIR 3
int redir = NONE_REDIR;
std::string filename;
// 接口
// 用户名
const char* getUser()
{
	char* name = getenv("USER");
	return name == NULL ? "None" : name;
}
// 当前路径
const char* getPwd()
{
	char* pwd = getenv("PWD");
	return pwd == NULL ? "None" : pwd;
}
// 主机
const char* getHostName()
{
	if (gethostname(hostName,sizeof(hostName))<0)
	{
		perror("没有得到主机名!\n");
		exit(1);
	}
	return hostName;
}
// home路径
const char* getHome()
{
	char* home = getenv("HOME");
	return home == NULL ? "" :home ; 
}
const char* getOldPwd()
{
	char* oldPwd = getenv("OLDPWD");
	return oldPwd == NULL ? "" : oldPwd;
}

void MakeCommandLine(char cmd_prompt[],size_t size)
{
	snprintf(cmd_prompt,size,FORMAT,getUser(),getPwd(),getHostName());
}

void PrintCommandLine()
{
	char prompt[COMMANDLINE];
	MakeCommandLine(prompt,COMMANDLINE);
	printf("%s",prompt);
	fflush(stdout);
}

bool GetCommandLine(char *out,size_t size)
{
	char *c = fgets(out,size,stdin);
	//printf("%s",out);
	if (c==NULL) return false;
	out[strlen(out)-1] = '\0';	
	if (strlen(out)==0) return false;
	return true;
}
bool CommandParse(char* commandLine)
{
#define SEP " "
	g_argc = 0;
	g_argv[g_argc++] = strtok(commandLine,SEP);
	while ((bool)(g_argv[g_argc++]=strtok(NULL,SEP)));
	g_argc--;// 不加不出现段错误 越界访问
	return true;

}
void PrintArgv()
{
	for(int i = 0;i<g_argc;i++)
	{
		printf("%s\n",g_argv[i]);
	}
}
int Execute()
{
	// 创建子进程
	pid_t id = fork();
	if (id == 0)
	{
		// 添加关于重定向的内容
		int fd = -1;
		if (redir == INPUT_REDIR)
		{
			fd = open(filename.c_str(),O_RDONLY);
			if (fd<0) exit(1);
			dup2(fd,0);
			close(fd);
		}
		else if (redir ==  OUTPUT_REDIR)
		{
			fd = open(filename.c_str(),O_CREAT|O_WRONLY|O_TRUNC,0666);
			if (fd < 0) exit(1);
			dup2(fd,1);
			close(fd);
		}
		else if (redir == APPEND_REDIR)
		{
			fd = open(filename.c_str(),O_CREAT|O_WRONLY|O_APPEND,0666);
			if (fd < 0) exit(1);
			dup2(fd,1);
			close(fd);
		}
		execvp(g_argv[0],g_argv);
		exit(1);
	}
	int status = 0;
    // father
    pid_t rid = waitpid(id, &status, 0);
    if(rid > 0)
    {
        lastcode = WEXITSTATUS(status);
    }
	return 0;
}
bool Cd()
{
    // 保存当前目录作为 OLDPWD
    char oldPwd[COMMANDLINE];
    if (getcwd(oldPwd, sizeof(oldPwd)) == NULL) {
        perror("getcwd");
        return false;
    }

    // 1. cd 无参数：跳到 HOME
    if (g_argc == 1)
    {
        const char* home = getHome();
        if (home == NULL || strlen(home) == 0) {
            fprintf(stderr, "cd: HOME not set\n");
            return false;
        }
        if (chdir(home) != 0) {
            perror("cd");
            return false;
        }
    }
    else
    {
        const char* where = g_argv[1];
        
        // ~ 返回到家目录
        if (strcmp(where, "~") == 0)
        {
            const char* home = getHome();
            if (home == NULL || strlen(home) == 0) {
                fprintf(stderr, "cd: HOME not set\n");
                return false;
            }
            if (chdir(home) != 0) {
                perror("cd");
                return false;
            }
        }
        // - 返回到上一个路径
        else if (strcmp(where, "-") == 0)
        {
            const char* envOldPwd = getOldPwd();
            if (envOldPwd == NULL || strlen(envOldPwd) == 0) {
                fprintf(stderr, "cd: OLDPWD not set\n");
                return false;
            }
            if (chdir(envOldPwd) != 0) {
                perror("cd");
                return false;
            }
            // 显示新目录（符合 bash 行为）
            char cwd[COMMANDLINE];
            getcwd(cwd, sizeof(cwd));
            printf("%s\n", cwd);
        }
        // . 保持当前目录
        else if (strcmp(where, ".") == 0)
        {
            // 什么都不做
        }
        // .. 跳到父目录
        else if (strcmp(where, "..") == 0)
        {
            if (chdir("..") != 0) {
                perror("cd");
                return false;
            }
        }
        // 其他路径
        else
        {
            if (chdir(where) != 0) {
                perror("cd");
                return false;
            }
        }
    }

    // 更新环境变量
    char newPwd[COMMANDLINE];
    if (getcwd(newPwd, sizeof(newPwd)) == NULL) {
        perror("getcwd");
        return false;
    }
    setenv("OLDPWD", oldPwd, 1);
    setenv("PWD", newPwd, 1);
    
    return true;
}
void Echo()
{
    if(g_argc == 2)
    {
        // echo "hello world"
        // echo $?
        // echo $PATH
        std::string opt = g_argv[1];
        if(opt == "$?")
        {
            std::cout << lastcode << std::endl;
            lastcode = 0;
        }
        else if(opt[0] == '$')
        {
            std::string env_name = opt.substr(1);
            const char *env_value = getenv(env_name.c_str());
            if(env_value)
                std::cout << env_value << std::endl;
        }
        else
        {
            std::cout << opt << std::endl;
        }
    }
}
bool CheckAndExecBuiltin()
{
	// 1. 获得命令
	char* command = g_argv[0];
	if (strcmp(command , "cd")==0)
	{
		Cd();
		return true;
	}
	else if (strcmp(command,"echo")==0)
	{
		Echo();
		return true;
	}
	// 等等
	return false;
}
void InitEnv()
{
	extern char** environ;
	memset(g_env,0,sizeof(g_env));
	g_envs = 0;

	// 从父进程得到环境变量
	for(int i = 0;environ[i];i++)
	{
		g_env[i] = (char*)malloc(strlen(environ[i])+1);
		strcpy(g_env[i],environ[i]);
		g_envs++;	
	}
	g_env[g_envs++] = (char*)"HAHA=123456";
	g_env[g_envs] = NULL;

	// 导出环境变量
	for(int i = 0;g_env[i];i++)
	{
		putenv(g_env[i]);
	}
	environ = g_env;
}
void Cleanup()
{
    for(int i = 0; i < g_envs; i++) {
        free(g_env[i]);
    }
}
void TrimSpace(char cmd[],int& end)
{
	while (isspace(cmd[end]))
		end++;
}
// 判断命令行是否是重定向
void RedirCheck(char cmd[])
{
	// ls -a -l > log.txt (>> , <)
	redir = NONE_REDIR;
	filename.clear();
	int start = 0;
	int end = strlen(cmd) - 1;
	// 从前往后找
	while (end > start)
	{
		if (cmd[end] == '<')
		{
			cmd[end++]= 0;
			TrimSpace(cmd,end);
			redir = INPUT_REDIR;
			filename = cmd + end;
			break;
		}
		else if (cmd[end] == '>')
		{
			if (cmd[end-1] == '>')
			{
				cmd[end-1] = 0;
				redir = APPEND_REDIR;
			}
			else
			{
				// >
				redir = OUTPUT_REDIR;
			}
			cmd[end++] = 0;
			TrimSpace(cmd,end);
			filename = cmd + end;
			break;
		}
		else
		{
			end--;
		}
	}
}
int main()
{
	InitEnv();
	while(1)
	{
		// 1. 输入命令行参数
		PrintCommandLine();
		// 2. 获得命令行
		char commandLine[COMMANDLINE];
		if(!GetCommandLine(commandLine,COMMANDLINE))
			continue;
		// 2.1. 需要判断命令是否是 ls -a -l > log.txt (>> , <)
		RedirCheck(commandLine);
		
		// 3. 解析命令行
		if (!CommandParse(commandLine))
			continue;
//		PrintArgv();	
		// 3.1. 是否是内建命令
		if (CheckAndExecBuiltin())
			continue;
		// 4. 执行命令行
		Execute();		
	}
	Cleanup();
	return 0;
}

